package cn.zglbk.data.csv;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.Serializable;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author zglbk.cn
 * @email 1030681978@qq.com
 * @date 2020/12/3 23:22
 */
public class FileHandler<T extends FileTable> {
    private final Logger log = LoggerFactory.getLogger(FileHandler.class);
    private int row;
    private Map<String, Integer> mapName2Index;
    private String[][] table;
    private Map<Serializable, T> mapData;
    private Class<T> clazz;

    FileHandler() {
        row = 0;
        mapName2Index = new HashMap<>();
        mapData = new HashMap<>();
    }

    T getById(Serializable id) {
        return mapData.get(id);
    }

    List<T> getArr() {
        return new ArrayList<>(mapData.values());
    }

    Map<Serializable, T> getMap() {
        return new HashMap<>(this.mapData);
    }

    private void unInit() {
        this.table = null;
        this.mapName2Index.clear();
        this.mapName2Index = null;
        this.clazz = null;
        this.row = 0;
    }

    boolean init(String path, Class<T> clazz) {
        this.clazz = clazz;
        int col = -1;
        //Files.newBufferedReader(Paths.get(path))
        try (BufferedReader bf = new BufferedReader(new FileReader(new File(path)))) {
            List<String> collect = bf.lines().collect(Collectors.toList());
            this.row = collect.size();
            int rowTemp = 0;
            for (String str : collect) {
                String[] split = str.split("\t", -1);
                if (col == -1) {
                    col = split.length;
                    table = new String[row][col];
                    for (int i = 0; i < col; i++) {
                        mapName2Index.put(split[i], i);
                    }
                } else if (split.length != col) {
                    log.error("读表格式不正确{}", path);
                    return false;
                }
                for (int i = 0; i < col; i++) {
                    table[rowTemp][i] = split[i];
                }
                rowTemp++;
            }
            row = 2;
            return create();
        } catch (Exception e) {
            log.error("",e);
            return false;
        }
    }

    private boolean create() {
        for (int i = 2; i < table.length; i++) {
            try {
                row = i;
                T t = clazz.getConstructor(FileHandler.class).newInstance(this);
                int id = t.getId();
                this.mapData.put(id, t);
            } catch (Exception e) {
                log.error("创建{}对象异常", clazz, e);
                return false;
            }
        }
        unInit();
        return true;
    }

    public int readInt(String key) {
        int index = this.mapName2Index.getOrDefault(key, -1);
        checkIndex(index, key);
        return Integer.parseInt(value(table[row][index]));
    }

    public long readLong(String key) {
        int index = this.mapName2Index.getOrDefault(key, -1);
        checkIndex(index, key);
        return Long.parseLong(value(table[row][index]));
    }

    public float readFloat(String key) {
        int index = this.mapName2Index.getOrDefault(key, -1);
        checkIndex(index, key);
        return Float.parseFloat(value(table[row][index]));
    }

    public double readDouble(String key) {
        int index = this.mapName2Index.getOrDefault(key, -1);
        checkIndex(index, key);
        return Double.parseDouble(value(table[row][index]));
    }

    public short readShort(String key) {
        int index = this.mapName2Index.getOrDefault(key, -1);
        checkIndex(index, key);
        return Short.parseShort(value(table[row][index]));
    }

    public byte readByte(String key) {
        int index = this.mapName2Index.getOrDefault(key, -1);
        checkIndex(index, key);
        return Byte.parseByte(value(table[row][index]));
    }

    public String readString(String key) {
        int index = this.mapName2Index.getOrDefault(key, -1);
        checkIndex(index, key);
        return value(table[row][index]);
    }

    public boolean readBoolean(String key) {
        int index = this.mapName2Index.getOrDefault(key, -1);
        checkIndex(index, key);
        String value = value(table[row][index]);
        if (StringUtils.isEmpty(value)) {
            return false;
        } else if ("0".equals(value)) {
            return false;
        } else if ("1".equals(value)) {
            return true;
        } else if ("y".equalsIgnoreCase(value)) {
            return true;
        } else if ("n".equalsIgnoreCase(value)) {
            return false;
        }
        return false;
    }

    private String value(String value) {
        if (StringUtils.isEmpty(value)) {
            value = "0";
        }
        return value;
    }

    private void checkIndex(int index, String key) {
        if (index < 0 || index > this.table.length) {
            log.error("{}赋值字段{}异常，数组下表{}越界", clazz, key, index);
            throw new RuntimeException("赋值字段异常，数组下表越界");
        }
    }
}
